/*
 * Copyright (c) 2022-2023 cetcclout Co., Ltd All rights reserved.
 * Sensor Adapter is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *          http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */
package com.cetccloud.cimp.common.util;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSONUtil;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;

import com.xy.format.hbt212.core.T212Mapper;
import com.xy.format.hbt212.core.feature.VerifyFeature;
import com.xy.format.hbt212.model.standard.Data;
import lombok.extern.slf4j.Slf4j;

/**
 * @author
 * @apiNote 环境监测国标（HJ-212）下的CRC校验
 * CRC 校验（Cyclic Redundancy Check）是一种数据传输错误检查方法。本标准采用 ANSI CRC16，
 * 简称 CRC16。
 * CRC16 码由传输设备计算后加入到数据包中。接收设备重新计算接收数据包的 CRC16 码，并与接
 * 收到的 CRC16 码比较，如果两值不同，则有误。
 * CRC16 校验字节的生成步骤如下：
 * 1) CRC16 校验寄存器赋值为 0xFFFF；
 * 2) 取被校验串的第一个字节赋值给临时寄存器；
 * 3) 临时寄存器与 CRC16 校验寄存器的高位字节进行“异或”运算，赋值给 CRC16 校验寄存器；
 * 4) 取 CRC16 校验寄存器最后一位赋值给检测寄存器；
 * 5) 把 CRC16 校验寄存器右移一位；
 * 6) 若检测寄存器值为 1，CRC16 校验寄存器与多项式 0xA001 进行“异或”运算，赋值给 CRC16
 * 校验寄存器；
 * 7) 重复步骤 4~6，直至移出 8 位；
 * 8) 取被校验串的下一个字节赋值给临时寄存器；
 * 9) 重复步骤 3~8，直至被校验串的所有字节均被校验；
 * 10) 返回 CRC16 校验寄存器的值。
 * 校验码按照先高字节后低字节的顺序存放。
 * @date 2023/2/7 11:15
 */
@Slf4j
public class EnvCrc16Utils {

    /**
     * 一个字节包含位的数量 8
     */
    private static final int BITS_OF_BYTE = 8;

    /**
     * 多项式
     */
    private static final int POLYNOMIAL = 0xA001;

    /**
     * 初始值
     */
    private static final int INITIAL_VALUE = 0xFFFF;

    /**
     * CRC16 编码
     * @param bytes 编码内容
     * @return 编码结果
     */
    public static String crc16(byte[] bytes) {
        int res = INITIAL_VALUE;
        for (int data : bytes) {
            res = (res >> 8) ^ data;
            for (int i = 0; i < BITS_OF_BYTE; i++) {
                res = (res & 0x0001) == 1 ? (res >> 1) ^ POLYNOMIAL : res >> 1;
            }
        }
        return convertToHexString(res);
    }

    /**
     * 获取验证码byte数组，基于Modbus CRC16的校验算法
     */
    private static String getCrc16(byte[] arr_buff) {
        int len = arr_buff.length;

        // 预置 1 个 16 位的寄存器为十六进制FFFF, 称此寄存器为 CRC寄存器。
        int crc = INITIAL_VALUE;
        int i, j;
        for (i = 0; i < len; i++) {
            // 把第一个 8 位二进制数据 与 16 位的 CRC寄存器的低 8 位相异或, 把结果放于 CRC寄存器
            crc =  (crc >> 8)  ^ arr_buff[i];
            for (j = 0; j < 8; j++) {
                // 把 CRC 寄存器的内容右移一位( 朝低位)用 0 填补最高位, 并检查右移后的移出位
                if ((crc & 0x0001) > 0) {
                    // 如果移出位为 1, CRC寄存器与多项式A001进行异或
                    crc = crc >> 1;
                    crc = crc ^ 0xA001;
                } else
                    // 如果移出位为 0,再次右移一位
                    crc = crc >> 1;
            }
        }
        return convertToHexString(crc);
    }

    /**
     * 翻转16位的高八位和低八位字节
     * @param src 翻转数字
     * @return 翻转结果
     */
    private static int revert(int src) {
        int lowByte = (src & 0xFF00) >> 8;
        int highByte = (src & 0x00FF) << 8;
        return lowByte | highByte;
    }

    /**
     * 整型转成16进制字符串
     * @param src 
     * @return
     */
    private static String convertToHexString(int src) {
        return Integer.toHexString(src).toUpperCase();
    }
    
  //生成模拟的数据包
    //##0384ST=31;CN=2061;PW=123456;MN=LD130124000302;CP=&&DataTime=20180119130000;B02-Cou=861042.56,B02-Min=237.43,B02-Rtd=239.18,B02-Max=241.41;02-Cou=3543.32,02-Min=3589.22,02-Rtd=4115.15,02-Flag=N;S08-Min=2000.000000,S08-Rtd=2000.000000,S08-Max=2000.000000;S03-Min=144.6,S03-Rtd=145.3,S03-Max=145.7;S01-Min=4.6,S01-Rtd=6.1,S01-Max=7.8;02-ZsMin=4054.17,02-ZsAvg=4129.43,02-ZsMax=4186.73&&8641
    public static String createTestData(String type, String deviceId, String dataTime, String interval){
        StringBuilder dataPackage = new StringBuilder();
        dataPackage.append("##");

        StringBuilder dataBlock = new StringBuilder();
        //长度统计开始点
        dataBlock.append("ST="+type.replace("I","")+";CN="+ interval +";PW=123456;");
        dataBlock.append("MN="+deviceId+";");
        //数据区
        dataBlock.append("CP=&&");
        dataBlock.append("DataTime="+ dataTime +";");

        Map<String, Object> randomData = new HashMap<>(0);
        //气象
        if(type.equals("I28")) {
            DateTime nowTimeKey = new DateTime(DateUtil.now(), "yyyy-MM-dd HH");
            String nowYear = nowTimeKey.year() + "";
            //excel中日期去除year后得剩余时间作为key
            String qxExcelMMDDHHKey = nowTimeKey.toString().replace(nowYear, "");
            randomData = (Map<String, Object>) DataConfig.qxMapData.get(qxExcelMMDDHHKey);
        }else if(type.equals("I22")) {
            DateTime nowTimeKey = new DateTime(DateUtil.now(), "yyyy-MM-dd HH");
            String nowYear = nowTimeKey.year() + "";
            //excel中日期去除year后得剩余时间作为key
            String qxExcelMMDDHHKey = nowTimeKey.toString().replace(nowYear, "");
            randomData = (Map<String, Object>) DataConfig.airMapData.get(qxExcelMMDDHHKey);
        }else {
            //取出随机数
            List<Map<String, Object>> rowData = DataConfig.mapData.get(type);
            if (rowData == null || rowData.size() == 0) {
                return "";
            }
            Random random = new Random();
            randomData = rowData.get(random.nextInt(rowData.size()));
        }
        if(randomData!=null&&randomData.size()>0) {
            switch (type) {
                case "I22": {
                    //大气指标 ok
                    switch (interval) {
                        case "2011": {
                            AirSixDataCreator.createAirRtdData(deviceId, dataBlock, randomData);
                            //createAirData(deviceId, dataBlock, randomData);
                        }
                        break;
                        case "2051": {
                            //十分钟统计数据
                            AirSixDataCreator.createAirMinuteData(deviceId, dataBlock);
                            //createAirDataMinute(deviceId, dataBlock);
                        }
                        break;
                        case "2061": {
                            //每小时统计数据
                            AirSixDataCreator.createAirHourData(deviceId, dataBlock);
                            //createAirDataHour(deviceId, dataBlock);
                        }
                        break;
                    }
                }
                break;
                case "I21": {
                    //地表水指标
                    switch (interval) {
                        case "2011": {
                            createFaceWaterData(deviceId, dataBlock, randomData);
                        }
                        break;
                        case "2051": {
                            //十分钟统计数据
                            createFaceWaterDataMinute(deviceId, dataBlock);
                        }
                        break;
                        case "2061": {
                            //每小时统计数据
                            createFaceWaterDataHour(deviceId, dataBlock);
                        }
                        break;
                    }
                }
                break;
                case "I31": {
                    //废气 ok
                    //createExhaustGasData(dataBlock,randomData);
                    switch (interval) {
                        case "2011": {
                            ExhaustGasCreator.createExhaustGasRtdData(deviceId, dataBlock, randomData);
                        }
                        break;
                        case "2051": {
                            //十分钟统计数据
                            ExhaustGasCreator.createExhaustGasMinuteData(deviceId, dataBlock);
                        }
                        break;
                        case "2061": {
                            //每小时统计数据
                            ExhaustGasCreator.createExhaustGasHourData(deviceId, dataBlock);
                        }
                        break;
                    }
                }
                break;
                case "I32": {
                    //废水 ok
                    //createSewageRainData(dataBlock,randomData);
                    switch (interval) {
                        case "2011": {
                            WasteWaterCreator.createWasteWaterRtdData(deviceId, dataBlock, randomData);
                        }
                        break;
                        case "2051": {
                            //十分钟统计数据
                            WasteWaterCreator.createWasteWaterMinuteData(deviceId, dataBlock);
                        }
                        break;
                        case "2061": {
                            //每小时统计数据
                            WasteWaterCreator.createWasteWaterHourData(deviceId, dataBlock);
                        }
                        break;
                    }
                }
                break;
                case "I28": {

                    //气象
                    switch (interval) {
                        case "2011": {
                            //将excel中时间中的年份,换成当前年
                            WeatherJtCreator.createQiXiangRtdData(deviceId, dataBlock, randomData);
                        }
                        break;
                        case "2051": {
                            //十分钟统计数据
                            WeatherJtCreator.createQiXiangMinuteData(deviceId, dataBlock);
                        }
                        break;
                        case "2061": {
                            //每小时统计数据
                            WeatherJtCreator.createQiXiangHourData(deviceId, dataBlock);
                        }
                        break;
                    }
                };
                break;
            }
            dataBlock.append("&&");
            //计算数据区长度
            int length = dataBlock.length();
            String lenStr = "0000".substring(0, 4 - String.valueOf(length).length()) + length;
            dataPackage.append(lenStr);

            //CRC
            String crc = crc16(dataBlock.toString().getBytes());
            dataBlock.append(("0000".substring(0, 4 - crc.length()) + crc));

            dataPackage.append(dataBlock);
            dataPackage.append("\r\n");
            return dataPackage.toString();
        }else{
            return null;
        }

    }

    /**
     * @author kehaofei
     * TODO 生成大气六项指标数据
     *
     * @param deviceId
     * @param dataBlock
     * @param randomData
     * @date 2023/2/28 15:01
     */
    private static void createAirData(String deviceId, StringBuilder dataBlock, Map<String, Object> randomData) {

        //SO2
        dataBlock.append("a21026-Rtd="+ randomData.get("二氧化硫实时浓度(μg/m³)") +",a21026-Flag=N;");
        //NO2
        dataBlock.append("a21004-Rtd="+ randomData.get("二氧化氮实时浓度(μg/m³)") +",a21004-Flag=N;");
        //CO
        dataBlock.append("a21005-Rtd="+ randomData.get("一氧化碳实时浓度(mg/m³)") +",a21005-Flag=N;");
        //O3
        dataBlock.append("a05024-Rtd="+ randomData.get("臭氧实时浓度(μg/m³)") +",a05024-Flag=N;");
        //PM10
        dataBlock.append("a34002-Rtd="+ randomData.get("PM10实时浓度(μg/m³)") +",a34002-Flag=N;");
        //PM2.5
        dataBlock.append("a34004-Rtd="+ randomData.get("PM2.5实时浓度(μg/m³)") +",a34004-Flag=N");


        List<Double> SO2 = DataConfig.MINUTE_DATA.get(deviceId,"a21026")==null?new ArrayList<>():DataConfig.MINUTE_DATA.get(deviceId,"a21026");
        SO2.add(Double.valueOf(randomData.get("二氧化硫实时浓度(μg/m³)").toString()));
        DataConfig.MINUTE_DATA.put(deviceId, "a21026", SO2);

        List<Double> NO2 = DataConfig.MINUTE_DATA.get(deviceId,"a21004")==null?new ArrayList<>():DataConfig.MINUTE_DATA.get(deviceId,"a21004");
        NO2.add(Double.valueOf(randomData.get("二氧化氮实时浓度(μg/m³)").toString()));
        DataConfig.MINUTE_DATA.put(deviceId, "a21004", NO2);

        List<Double> CO = DataConfig.MINUTE_DATA.get(deviceId,"a21005")==null?new ArrayList<>():DataConfig.MINUTE_DATA.get(deviceId,"a21005");
        CO.add(Double.valueOf(randomData.get("一氧化碳实时浓度(mg/m³)").toString()));
        DataConfig.MINUTE_DATA.put(deviceId, "a21005", CO);

        List<Double> O3 = DataConfig.MINUTE_DATA.get(deviceId,"a05024")==null?new ArrayList<>():DataConfig.MINUTE_DATA.get(deviceId,"a05024");
        O3.add(Double.valueOf(randomData.get("臭氧实时浓度(μg/m³)").toString()));
        DataConfig.MINUTE_DATA.put(deviceId, "a05024", O3);

        List<Double> PM10 = DataConfig.MINUTE_DATA.get(deviceId,"a34002")==null?new ArrayList<>():DataConfig.MINUTE_DATA.get(deviceId,"a34002");
        PM10.add(Double.valueOf(randomData.get("PM10实时浓度(μg/m³)").toString()));
        DataConfig.MINUTE_DATA.put(deviceId, "a34002", PM10);

        List<Double> PM25 = DataConfig.MINUTE_DATA.get(deviceId,"a34004")==null?new ArrayList<>():DataConfig.MINUTE_DATA.get(deviceId,"a34004");
        PM25.add(Double.valueOf(randomData.get("PM2.5实时浓度(μg/m³)").toString()));
        DataConfig.MINUTE_DATA.put(deviceId, "a34004", PM25);

    }
    private static void createAirDataMinute(String deviceId, StringBuilder dataBlock) {
        //SO2
        dataBlock.append(getDataMinute(deviceId,"a21026"));
        //NO2
        dataBlock.append(getDataMinute(deviceId,"a21004"));
        //CO a21005
        dataBlock.append(getDataMinute(deviceId,"a21005"));
        //O3 a05024
        dataBlock.append(getDataMinute(deviceId,"a05024"));
        //PM10 a34002
        dataBlock.append(getDataMinute(deviceId,"a34002"));
        //PM2.5 a34004
        dataBlock.append(getDataMinute(deviceId,"a34004").replace(";",""));

        //处理完毕数据后清空
        DataConfig.MINUTE_DATA.get(deviceId,"a21026").clear();
        DataConfig.MINUTE_DATA.get(deviceId,"a21004").clear();
        DataConfig.MINUTE_DATA.get(deviceId,"a21005").clear();
        DataConfig.MINUTE_DATA.get(deviceId,"a05024").clear();
        DataConfig.MINUTE_DATA.get(deviceId,"a34002").clear();
        DataConfig.MINUTE_DATA.get(deviceId,"a34004").clear();
        log.info("十分钟数据：{}",JSONUtil.toJsonStr(DataConfig.MINUTE_DATA));
    }
    private static void createAirDataHour(String deviceId, StringBuilder dataBlock) {

        //SO2
        dataBlock.append(getDataHour(deviceId,"a21026"));
        //NO2
        dataBlock.append(getDataHour(deviceId,"a21004"));
        //CO a21005
        dataBlock.append(getDataHour(deviceId,"a21005"));
        //O3 a05024
        dataBlock.append(getDataHour(deviceId,"a05024"));
        //PM10 a34002
        dataBlock.append(getDataHour(deviceId,"a34002"));
        //PM2.5 a34004
        dataBlock.append(getDataHour(deviceId,"a34004").replace(";",""));

        //处理完毕数据后清空
        DataConfig.HOUR_DATA.get(deviceId,"a21026").clear();
        DataConfig.HOUR_DATA.get(deviceId,"a21004").clear();
        DataConfig.HOUR_DATA.get(deviceId,"a21005").clear();
        DataConfig.HOUR_DATA.get(deviceId,"a05024").clear();
        DataConfig.HOUR_DATA.get(deviceId,"a34002").clear();
        DataConfig.HOUR_DATA.get(deviceId,"a34004").clear();
        log.info("小时数据：{}",JSONUtil.toJsonStr(DataConfig.HOUR_DATA));
    }

    /**
     * @author kehaofei
     * TODO  地表水
     *
     * @param deviceId
     * @param dataBlock
     * @param randomData
     * @date 2023/3/1 11:02
     */
    private static void createFaceWaterData(String deviceId, StringBuilder dataBlock, Map<String, Object> randomData) {

        //电导率 w01014
        dataBlock.append("w01014-Rtd="+ randomData.get("电导率(μS/cm)") +",w01014-Flag=N;");
        //色度（浊度） w01002
        dataBlock.append("w01002-Rtd="+ randomData.get("浊度(NTU)") +",w01002-Flag=N;");
        //总氮 w21001
        dataBlock.append("w21001-Rtd="+ randomData.get("总氮(mg/L)") +",w21001-Flag=N;");
        //化学需氧量 w01018
        dataBlock.append("w01018-Rtd="+ randomData.get("化学需氧量(mg/L)") +",w01018-Flag=N;");
        //水温 w01010
        dataBlock.append("w01010-Rtd="+ randomData.get("水温(℃)") +",w01010-Flag=N;");

        //总磷 w21011
        dataBlock.append("w21011-Rtd="+ randomData.get("总磷(mg/L)") +",w21011-Flag=N;");
        //氨氮(0.15,0.5] w21003
        dataBlock.append("w21003-Rtd="+ randomData.get("氨氮(mg/L)") +",w21003-Flag=N;");
        //高锰酸盐 w01019
        dataBlock.append("w01019-Rtd="+ randomData.get("高锰酸盐指数(mg/L)") +",w01019-Flag=N;");
        //溶解氧 w01009
        dataBlock.append("w01009-Rtd="+ randomData.get("溶解氧(mg/L)") +",w01009-Flag=N;");
        //PH w01001
        dataBlock.append("w01001-Rtd="+ randomData.get("pH值(无量纲)") +",w01001-Flag=N");

        List<Double> w01014 = DataConfig.MINUTE_DATA.get(deviceId,"w01014")==null?new ArrayList<>():DataConfig.MINUTE_DATA.get(deviceId,"w01014");
        w01014.add(Double.valueOf(randomData.get("电导率(μS/cm)").toString()));
        DataConfig.MINUTE_DATA.put(deviceId, "w01014", w01014);

        List<Double> w01002 = DataConfig.MINUTE_DATA.get(deviceId,"w01002")==null?new ArrayList<>():DataConfig.MINUTE_DATA.get(deviceId,"w01002");
        w01002.add(Double.valueOf(randomData.get("浊度(NTU)").toString()));
        DataConfig.MINUTE_DATA.put(deviceId, "w01002", w01002);

        List<Double> w21001 = DataConfig.MINUTE_DATA.get(deviceId,"w21001")==null?new ArrayList<>():DataConfig.MINUTE_DATA.get(deviceId,"w21001");
        w21001.add(Double.valueOf(randomData.get("总氮(mg/L)").toString()));
        DataConfig.MINUTE_DATA.put(deviceId, "w21001", w21001);

        List<Double> w01018 = DataConfig.MINUTE_DATA.get(deviceId,"w01018")==null?new ArrayList<>():DataConfig.MINUTE_DATA.get(deviceId,"w01018");
        w01018.add(Double.valueOf(randomData.get("化学需氧量(mg/L)").toString()));
        DataConfig.MINUTE_DATA.put(deviceId, "w01018", w01018);

        List<Double> w01010 = DataConfig.MINUTE_DATA.get(deviceId,"w01010")==null?new ArrayList<>():DataConfig.MINUTE_DATA.get(deviceId,"w01010");
        w01010.add(Double.valueOf(randomData.get("水温(℃)").toString()));
        DataConfig.MINUTE_DATA.put(deviceId, "w01010", w01010);

        List<Double> w21011 = DataConfig.MINUTE_DATA.get(deviceId,"w21011")==null?new ArrayList<>():DataConfig.MINUTE_DATA.get(deviceId,"w21011");
        w21011.add(Double.valueOf(randomData.get("总磷(mg/L)").toString()));
        DataConfig.MINUTE_DATA.put(deviceId, "w21011", w21011);

        List<Double> w21003 = DataConfig.MINUTE_DATA.get(deviceId,"w21003")==null?new ArrayList<>():DataConfig.MINUTE_DATA.get(deviceId,"w21003");
        w21003.add(Double.valueOf(randomData.get("氨氮(mg/L)").toString()));
        DataConfig.MINUTE_DATA.put(deviceId, "w21003", w21003);

        List<Double> w01019 = DataConfig.MINUTE_DATA.get(deviceId,"w01019")==null?new ArrayList<>():DataConfig.MINUTE_DATA.get(deviceId,"w01019");
        w01019.add(Double.valueOf(randomData.get("高锰酸盐指数(mg/L)").toString()));
        DataConfig.MINUTE_DATA.put(deviceId, "w01019", w01019);

        List<Double> w01009 = DataConfig.MINUTE_DATA.get(deviceId,"w01009")==null?new ArrayList<>():DataConfig.MINUTE_DATA.get(deviceId,"w01009");
        w01009.add(Double.valueOf(randomData.get("溶解氧(mg/L)").toString()));
        DataConfig.MINUTE_DATA.put(deviceId, "w01009", w01009);

        List<Double> w01001 = DataConfig.MINUTE_DATA.get(deviceId,"w01001")==null?new ArrayList<>():DataConfig.MINUTE_DATA.get(deviceId,"w01001");
        w01001.add(Double.valueOf(randomData.get("pH值(无量纲)").toString()));
        DataConfig.MINUTE_DATA.put(deviceId, "w01001", w01001);
    }


    private static void createFaceWaterDataMinute(String deviceId, StringBuilder dataBlock) {

        //电导率 w01014
        dataBlock.append(getDataMinute(deviceId,"w01014"));
        //色度（浊度） w01002
        dataBlock.append(getDataMinute(deviceId,"w01002"));
        //总氮 w21001
        dataBlock.append(getDataMinute(deviceId,"w21001"));
        //化学需氧量 w01018
        dataBlock.append(getDataMinute(deviceId,"w01018"));
        //水温 w01010
        dataBlock.append(getDataMinute(deviceId,"w01010"));
        //总磷 w21011
        dataBlock.append(getDataMinute(deviceId,"w21011"));
        //氨氮(0.15,0.5] w21003
        dataBlock.append(getDataMinute(deviceId,"w21003"));
        //高锰酸盐 w01019
        dataBlock.append(getDataMinute(deviceId,"w01019"));
        //溶解氧 w01009
        dataBlock.append(getDataMinute(deviceId,"w01009"));
        //PH w01001
        dataBlock.append(getDataMinute(deviceId,"w01001").replace(";",""));

        //处理完毕数据后清空
        DataConfig.MINUTE_DATA.get(deviceId,"w01014").clear();
        DataConfig.MINUTE_DATA.get(deviceId,"w01002").clear();
        DataConfig.MINUTE_DATA.get(deviceId,"w21001").clear();
        DataConfig.MINUTE_DATA.get(deviceId,"w01018").clear();
        DataConfig.MINUTE_DATA.get(deviceId,"w01010").clear();
        DataConfig.MINUTE_DATA.get(deviceId,"w21011").clear();
        DataConfig.MINUTE_DATA.get(deviceId,"w21003").clear();
        DataConfig.MINUTE_DATA.get(deviceId,"w01019").clear();
        DataConfig.MINUTE_DATA.get(deviceId,"w01009").clear();
        DataConfig.MINUTE_DATA.get(deviceId,"w01001").clear();
        log.info("十分钟数据：{}",JSONUtil.toJsonStr(DataConfig.MINUTE_DATA));
    }

    private static void createFaceWaterDataHour(String deviceId, StringBuilder dataBlock) {
        //电导率 w01014
        dataBlock.append(getDataHour(deviceId,"w01014"));
        //色度（浊度） w01002
        dataBlock.append(getDataHour(deviceId,"w01002"));
        //总氮 w21001
        dataBlock.append(getDataHour(deviceId,"w21001"));
        //化学需氧量 w01018
        dataBlock.append(getDataHour(deviceId,"w01018"));
        //水温 w01010
        dataBlock.append(getDataHour(deviceId,"w01010"));
        //总磷 w21011
        dataBlock.append(getDataHour(deviceId,"w21011"));
        //氨氮(0.15,0.5] w21003
        dataBlock.append(getDataHour(deviceId,"w21003"));
        //高锰酸盐 w01019
        dataBlock.append(getDataHour(deviceId,"w01019"));
        //溶解氧 w01009
        dataBlock.append(getDataHour(deviceId,"w01009"));
        //PH w01001
        dataBlock.append(getDataHour(deviceId,"w01001").replace(";",""));

        //处理完毕数据后清空
        DataConfig.HOUR_DATA.get(deviceId,"w01014").clear();
        DataConfig.HOUR_DATA.get(deviceId,"w01002").clear();
        DataConfig.HOUR_DATA.get(deviceId,"w21001").clear();
        DataConfig.HOUR_DATA.get(deviceId,"w01018").clear();
        DataConfig.HOUR_DATA.get(deviceId,"w01010").clear();
        DataConfig.HOUR_DATA.get(deviceId,"w21011").clear();
        DataConfig.HOUR_DATA.get(deviceId,"w21003").clear();
        DataConfig.HOUR_DATA.get(deviceId,"w01019").clear();
        DataConfig.HOUR_DATA.get(deviceId,"w01009").clear();
        DataConfig.HOUR_DATA.get(deviceId,"w01001").clear();
        log.info("小时数据：{}",JSONUtil.toJsonStr(DataConfig.HOUR_DATA));
    }
    /**
     * @author wh
     * TODO  废气
     *
     * @param dataBlock
     * @param randomData
     * @date 2023/3/1 11:02
     */
    private static void createExhaustGasData(StringBuilder dataBlock, Map<String, Object> randomData) {

        //SO2 a21026
        dataBlock.append("a21026-Rtd="+ randomData.get("二氧化硫实时浓度(mg/m3)") +",a21026-Flag=N;");
        //NOx 氮氧化物 a21002
        dataBlock.append("a21002-Rtd="+ randomData.get("氮氧化物实时浓度(mg/m3)") +",a21002-Flag=N;");
        //颗粒物 a34000
        dataBlock.append("a34000-Rtd="+ randomData.get("颗粒物实时浓度(mg/m3)") +",a34001-Flag=N;");
        // VOCs  a24088 非甲烷总烃
        dataBlock.append("a24088-Rtd="+ randomData.get("???????") +",a24088-Flag=N;");
        // 流速
        dataBlock.append("a01011-Rtd="+ randomData.get("???????") +",a01011-Flag=N");

    }


    /**
     * @author wh
     * TODO  废水
     *
     * @param dataBlock
     * @param randomData
     * @date 2023/3/1 11:02
     */
    private static void createSewageRainData(StringBuilder dataBlock, Map<String, Object> randomData) {

        // 化学需氧量（COD）
        dataBlock.append("w01018-Rtd="+ randomData.get("二氧化硫实时浓度(μg/m³)") +",w01018-Flag=N;");
        //氨氮 三级:(na,25] w21003
        dataBlock.append("w21003-Rtd="+ randomData.get("二氧化氮实时浓度(μg/m³)") +",w21003-Flag=N;");
        //总磷 (0,1.0] 区分改为w21011
        dataBlock.append("w21011-Rtd="+ randomData.get("一氧化碳实时浓度(mg/m³)") +",w21011-Flag=N;");
        //总氮(0,15] 区分改为 w21001
        dataBlock.append("w21001-Rtd="+ randomData.get("臭氧实时浓度(μg/m³)") +",w21001-Flag=N;");
        //PH 出水口 PH e205xx  e20501
        dataBlock.append("e20501-Rtd="+ randomData.get("PM10实时浓度(μg/m³)") +",e20501-Flag=N;");
        // e201xx 出水口流量 e20101
        dataBlock.append("e20101-Rtd="+ randomData.get("PM2.5实时浓度(μg/m³)") +",e20101-Flag=N");


    }


    /**
     * 生成需要的十分钟模拟数据
     * @param deviceId
     * @param ID
     * @return
     */
    public static String getDataMinute(String deviceId, String ID){
        List<Double> rtdDataList = DataConfig.MINUTE_DATA.get(deviceId,ID);

        List<Double> hourData = DataConfig.HOUR_DATA.get(deviceId,ID)==null?new ArrayList<>():DataConfig.HOUR_DATA.get(deviceId,ID);
        hourData.addAll(rtdDataList);
        DataConfig.HOUR_DATA.put(deviceId,ID,hourData);
        //得到和
        double cou = rtdDataList.stream().mapToDouble( Double :: valueOf ).sum();
        //得到平均数
        double avg = rtdDataList.stream().mapToDouble( Double :: valueOf ).average().getAsDouble();
        //得到最小值
        double min = rtdDataList.stream().mapToDouble( Double :: valueOf ).min().getAsDouble();
        //得到最大值
        double max = rtdDataList.stream().mapToDouble( Double :: valueOf ).max().getAsDouble();

        String data = ID+"-Cou="+ cou +","+ ID +"-Min="+ min +","+ ID +"-Avg="+ avg +","+ ID +"-Max="+ max +";";
        return data;
    }

    /**
     * 生成需要的小时模拟数据
     * @param deviceId
     * @param ID
     * @return
     */
    public static String getDataHour(String deviceId, String ID){
        List<Double> rtdDataList = DataConfig.HOUR_DATA.get(deviceId,ID);
        //得到和
        double cou = rtdDataList.stream().mapToDouble( Double :: valueOf ).sum();
        //得到平均数
        double avg = rtdDataList.stream().mapToDouble( Double :: valueOf ).average().getAsDouble();
        //得到最小值
        double min = rtdDataList.stream().mapToDouble( Double :: valueOf ).min().getAsDouble();
        //得到最大值
        double max = rtdDataList.stream().mapToDouble( Double :: valueOf ).max().getAsDouble();

        String data = ID+"-Cou="+ cou +","+ ID +"-Min="+ min +","+ ID +"-Avg="+ avg +","+ ID +"-Max="+ max +";";
        return data;
    }

    public static void main(String[] args) {
        String s="ST=32;CN=2051;PW=123456;MN=ZG130129201728;CP=&&DataTime=20180118235900;B02-Min=0.6800,B02-Avg=0.7322,B02-Max=0.8400,B02-Cou=43.9333;S07-Min=2.8300,S07-Avg=2.8300,S07-Max=2.8300,S07-Cou=2.8300;S05-Min=8.0000,S05-Avg=8.0000,S05-Max=8.0000,S05-Cou=8.0000;S03-Min=5.6600,S03-Avg=5.6956,S03-Max=5.7500,S03-Cou=5.6956;S08-Min=-0.1300,S08-Avg=-0.1293,S08-Max=0.0000,S08-Cou=-0.1293;S02-Min=0.2700,S02-Avg=0.2878,S02-Max=0.3300,S02-Cou=0.2878;S01-Min=20.8000,S01-Avg=20.8000,S01-Max=20.8000,S01-Cou=20.8000;01-Min=11.4000,01-Avg=11.5267,01-Max=11.7800,01-Cou=0.0005;01-ZsMin=11.4000,01-ZsAvg=11.5267,01-ZsMax=11.7800;02-Min=0.0000,02-Avg=0.0000,02-Max=0.0000,02-Cou=0.0000;02-ZsMin=0.0000,02-ZsAvg=0.0000,02-ZsMax=0.0000;03-Min=0.0000,03-Avg=0.0000,03-Max=0.0000,03-Cou=0.0000;03-ZsMin=0.0000,03-ZsAvg=0.0000,03-ZsMax=0.0000&&";
        String a = "QN=20200826094652892;ST=22;CN=2011;PW=852013;MN=010000A8900016F000169DC0;Flag=4;CP=&&DataTime=20200826094652;A1001-Rtd=65436;A1001-Rtd=65336;A1001-Rtd=65236;A1001-Rtd=28926;A1001-Rtd=3326;A1001-Rtd=8000;A1001-Rtd=8000;A1001-Rtd=8000;A1001-Rtd=8000;A1001-Rtd=8000;A1001-Rtd=16415;A1001-Rtd=16415;A1001-Rtd=16415;A1001-Rtd=16415;A1001-Rtd=3326&&";
        System.out.println(crc16(s.getBytes()));


        //T212Mapper 配置默认解析器和默认校验器
        String str = "##0948ST=31;CN=2051;PW=123456;MN=ZG130129201772;CP=&&DataTime=20180119003200;B02-Min=0.0000,B02-Avg=0.4200,B02-Max=1.8024,B02-Cou=25.2029;S01-Min=15.9074,S01-Avg=16.0782,S01-Max=16.3567,S01-Cou=16.0782;S02-Min=0.0000,S02-Avg=0.4299,S02-Max=1.8442,S02-Cou=0.4299;S03-Min=59.8247,S03-Avg=60.7032,S03-Max=61.5500,S03-Cou=60.7032;S08-Min=-0.0757,S08-Avg=-0.0749,S08-Max=0.0000,S08-Cou=-0.0749;01-Min=8.8408,01-Avg=9.1064,01-Max=9.2853,01-Cou=0.0002;01-ZsMin=21.9840,01-ZsAvg=22.8770,01-ZsMax=24.0538;02-Min=112.6284,02-Avg=117.4169,02-Max=121.6073,02-Cou=0.0030;02-ZsMin=283.1362,02-ZsAvg=294.9046,02-ZsMax=311.6977;03-Min=40.4385,03-Avg=41.2776,03-Max=41.7791,03-Cou=0.0010;03-ZsMin=100.0476,03-ZsAvg=103.7100,03-ZsMax=111.2191;08-Min=1.4631,08-Avg=1.5844,08-Max=1.6125,08-Cou=0.0000;08-ZsMin=3.6781,08-ZsAvg=3.9805,08-ZsMax=4.2924;S07-Min=1.3300,S07-Avg=1.3300,S07-Max=1.3300,S07-Cou=1.3300;S05-Min=10.0000,S05-Avg=10.0000,S05-Max=10.0000,S05-Cou=10.0000&&5CC0\r\n";
        try {
            T212Mapper mapper = new T212Mapper()
                    .enableDefaultVerifyFeatures()
                    .enable(VerifyFeature.DATA_CRC);//启用CRC校验


            Data data = mapper.readData(str);
            System.out.println("hj212数据为-- " + JSONUtil.toJsonStr(data));


        }catch (Exception e){
            log.error("hj-212 解析成Data对象数据出错--------------------");
            log.error("{}", e);
        }
    }
}
